﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using BPM.Foundation.WFDB;
using BPM.Base.Tools;
using System.Data;

namespace BPM.Foundation.WFService
{
    public partial interface IWorkflowService
    {
        [System.ServiceModel.OperationContract]
        int? refreshTransactResidualTimelimit();

        [System.ServiceModel.OperationContract]
        SYS_Calendar addCalendar(SYS_Calendar calendar);

        [System.ServiceModel.OperationContract]
        SYS_Period addPeriod(SYS_Period period);

        [System.ServiceModel.OperationContract]
        List<SYS_Period> addPeriods(List<SYS_Period> periods);

        [System.ServiceModel.OperationContract]
        SYS_Calendar updateCalendar(SYS_Calendar calendar);

        [System.ServiceModel.OperationContract]
        SYS_Period updatePeriod(SYS_Period period);

        [System.ServiceModel.OperationContract]
        List<SYS_Calendar> getAllCalendars();

        [System.ServiceModel.OperationContract]
        List<SYS_Period> getPeriods(Guid calendarID);

        [System.ServiceModel.OperationContract]
        int? deleteCalendar(SYS_Calendar calendar);

        [System.ServiceModel.OperationContract]
        int? deletePeriod(SYS_Period period);

        //根据月份、用户，查询处理任务超时总天数
        [System.ServiceModel.OperationContract]
        int? getTransactTotalTimeout(int month, string userNo);

        [System.ServiceModel.OperationContract]
        int? getInceptTotalTimeout(int month, string userNo);

        /// <summary>
        /// 单位时间内根据部门，查询部门用户的逾期待处理任务数量
        /// </summary>
        /// <param name="dptNo"></param>
        /// <param name="dtFrom"></param>
        /// <param name="dtTo"></param>
        /// <returns></returns>
        [System.ServiceModel.OperationContract]
        List<RP_TransactTimoutCount> getTransactTimeoutCount(string dptNo, DateTime dtFrom, DateTime dtTo);

    }

    public partial class WorkflowService : IWorkflowService
    {
        //[11.1	时间操作]
        public int? refreshTransactResidualTimelimit()
        {
            int i = 0;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                //时间计算
                try
                {
                    var delWfTimeouts = wfDB.WF_InstanceTimeout.ToList();
                    if (delWfTimeouts != null)
                    {
                        wfDB.WF_InstanceTimeout.DeleteAllOnSubmit(delWfTimeouts);
                    }
                    var f = wfDB.WF_InstanceState.Where(p => p.runState == "wait");
                    var wfTransactTimeoutHis = wfDB.WF_TransactTimeoutHistory.ToList();
                    var wfInceptTimeoutHis = wfDB.WF_InceptTimeoutHistory.ToList();
                    foreach (var v in f)
                    {
                        var wfi = wfDB.WF_Instance.SingleOrDefault(p => p.instanceID == v.instanceID);
                        var wfbf = wfDB.WF_BusinessForm.SingleOrDefault(a => (a.businessID == wfi.businessID && a.startWindow == v.startWindow));
                        int y = wfDB.SYS_Period.Where(a => (a.periodDate > v.createTime && a.periodDate <= DateTime.Today && a.isActive == 1)).Count();
                        v.transactResidualTimelimit = v.transactTimelimit - y;
                        v.inceptResidualTimelimit = v.inceptTimelimit - y;
                        if (v.transactResidualTimelimit < 0)//处理逾期
                        {
                            var his = wfTransactTimeoutHis.Find(a => a.stateInstanceID == v.stateInstanceID);
                            if (his != null)
                            {
                                his.transactResidualTimelimit = v.transactTimelimit - y;
                            }
                            else
                            {
                                var menu = wfDB.PW_Menu.Single(a => a.formName == v.startWindow);
                                WF_TransactTimeoutHistory wfTimeoutHistory = new WF_TransactTimeoutHistory
                                {
                                    instanceID = v.instanceID,
                                    stateInstanceID = v.stateInstanceID,
                                    transactUser = v.transactUser,
                                    transactTimelimit = v.transactTimelimit,
                                    transactResidualTimelimit = v.transactTimelimit - y,
                                    createTime = v.createTime,
                                    startWindow = v.startWindow,
                                    dataRowID = (wfbf == null ? null : wfbf.dataRowID),
                                    name = menu.menuName+":"+v.stateName
                                };
                                wfDB.WF_TransactTimeoutHistory.InsertOnSubmit(wfTimeoutHistory);
                            }
                        }
                        if (v.inceptResidualTimelimit < 0)//接件逾期
                        {
                            var his = wfInceptTimeoutHis.Find(a => a.stateInstanceID == v.stateInstanceID);
                            if (his != null)
                            {
                                his.inceptResidualTimelimit = v.inceptTimelimit - y;
                            }
                            else
                            {
                                WF_InceptTimeoutHistory wfTimeoutHistory = new WF_InceptTimeoutHistory
                                {
                                    instanceID = v.instanceID,
                                    stateInstanceID = v.stateInstanceID,
                                    inceptDepartment = v.inceptDepartment,
                                    inceptDuty = v.inceptDuty,
                                    inceptTimelimit = v.inceptTimelimit,
                                    inceptResidualTimelimit = v.inceptResidualTimelimit,
                                    createTime = v.createTime,
                                    startWindow = v.startWindow,
                                    dataRowID = (wfbf == null ? null : wfbf.dataRowID)
                                };
                                wfDB.WF_InceptTimeoutHistory.InsertOnSubmit(wfTimeoutHistory);
                            }
                        }
                        WF_InstanceTimeout wfTimeout = new WF_InstanceTimeout
                        {
                            instanceID = v.instanceID,
                            stateInstanceID = v.stateInstanceID,
                            inceptDepartment = v.inceptDepartment,
                            inceptDuty = v.inceptDuty,
                            inceptTimelimit = v.inceptTimelimit,
                            inceptResidualTimelimit = v.inceptResidualTimelimit,
                            transactUser = v.transactUser,
                            transactTimelimit = v.transactTimelimit,
                            transactResidualTimelimit = v.transactTimelimit - y,
                            createTime = v.createTime
                        };
                        wfDB.WF_InstanceTimeout.InsertOnSubmit(wfTimeout);
                    }
                    wfDB.SubmitChanges();
                }
                catch (System.Exception ex)
                {
                    MyLog.writeError(ex.Message);
                }

                //超时操作
                var t = wfDB.WF_InstanceState.Where(p => p.runState == "wait" && p.transactResidualTimelimit < 0 && p.transactOvertimeOperate != "" && p.transactUser != "");
                foreach (var v in t)
                {
                    SubmitResult sr = new SubmitResult();

                    sr.instanceID = v.instanceID;

                    sr.nextStateUserNo = "";

                    sr.stateInstanceID = v.stateInstanceID;

                    sr.submitDepartment = v.inceptDepartment;

                    sr.submitDescription = "超时操作";

                    sr.submitDuty = v.inceptDuty;

                    sr.submitMode = "system";

                    sr.submitResult = v.transactOvertimeOperate;

                    sr.submitTime = System.DateTime.Now;

                    sr.submitUser = v.transactUser;

                    sr.triggerType = "超时操作";

                    this.businessSubmit("", sr);
                    i = i + 1;

                }
            }
            return i;
        }

        public SYS_Calendar addCalendar(SYS_Calendar calendar)
        {
            if (calendar == null)
                return null;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                calendar.ID = Guid.NewGuid();
                calendar.createdDate = DateTime.Now;
                calendar.updatedDate = DateTime.Now;
                wfDB.SYS_Calendar.InsertOnSubmit(calendar);
                wfDB.SubmitChanges();
                return calendar;
            }
        }

        public SYS_Calendar updateCalendar(SYS_Calendar calendar)
        {
            if (calendar == null)
                return null;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                calendar.updatedDate = DateTime.Now;
                SYS_Calendar c = wfDB.SYS_Calendar.SingleOrDefault(a => a.ID == calendar.ID);
                if (c == null)
                    return null;
                c.isActive = calendar.isActive;
                c.createdBy = calendar.createdBy;
                c.createdDate = calendar.createdDate;
                c.updatedBy = calendar.updatedBy;
                c.updatedDate = calendar.updatedDate;
                c.name = calendar.name;
                c.description = calendar.description;
                c.periodType = calendar.periodType;
                wfDB.SubmitChanges();
                return c;
            }
        }

        public SYS_Period addPeriod(SYS_Period period)
        {
            if (period == null)
                return null;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                period.ID = Guid.NewGuid();
                wfDB.SYS_Period.InsertOnSubmit(period);
                wfDB.SubmitChanges();
                return period;
            }
        }

        public List<SYS_Period> addPeriods(List<SYS_Period> periods)
        {
            if (periods == null)
                return null;
            if (periods.Count == 0)
                return null;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                foreach (var p in periods)
                {
                    p.ID = Guid.NewGuid();
                }
                wfDB.SYS_Period.InsertAllOnSubmit(periods);
                wfDB.SubmitChanges();
                return periods;
            }
        }

        public SYS_Period updatePeriod(SYS_Period period)
        {
            if (period == null)
                return null;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                SYS_Period p = wfDB.SYS_Period.SingleOrDefault(a => a.ID == period.ID);
                if (p == null)
                    return null;
                p.isActive = period.isActive;
                p.year = period.year;
                p.month = period.month;
                p.day = period.day;
                p.calendarID = period.calendarID;
                p.type = period.type;
                wfDB.SubmitChanges();
                return p;
            }
        }

        public List<SYS_Calendar> getAllCalendars()
        {
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                return wfDB.SYS_Calendar.ToList();
            }
        }

        public List<SYS_Period> getPeriods(Guid calendarID)
        {
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                return wfDB.SYS_Period.Where(a => a.calendarID == calendarID).ToList();
            }
        }

        public int? deleteCalendar(SYS_Calendar calendar)
        {
            if (calendar == null)
                return 1;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                var c = wfDB.SYS_Calendar.Single(a => a.ID == calendar.ID);
                if (c == null)
                    return 2;
                var periods = wfDB.SYS_Period.Where(a => a.calendarID == calendar.ID);
                if (periods == null)
                {
                    wfDB.SYS_Period.DeleteAllOnSubmit(periods);
                    wfDB.SYS_Calendar.DeleteOnSubmit(c);
                }
                else
                {
                    wfDB.SYS_Calendar.DeleteOnSubmit(c);
                }
                wfDB.SubmitChanges();
                return null;
            }
        }

        public int? deletePeriod(SYS_Period period)
        {
            if (period == null)
                return 1;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                var p = wfDB.SYS_Period.Single(a => a.ID == period.ID);
                if (p == null)
                    return 2;
                wfDB.SYS_Period.DeleteOnSubmit(p);
                wfDB.SubmitChanges();
                return null;
            }
        }

        public int? getTransactTotalTimeout(int month, string userNo)
        {
            if (month == 0 || string.IsNullOrEmpty(userNo))
                return null;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                var result = wfDB.WF_TransactTimeoutHistory.Where(a => (a.createTime >= new DateTime(DateTime.Now.Year, month, 1) &&
                    a.createTime < new DateTime(DateTime.Now.Year, month, 1).AddMonths(1) &&
                    a.transactUser == userNo));
                if (result == null)
                    return null;
                if (result.Count() == 0)
                    return 0;
                return result.Sum(b => b.transactResidualTimelimit);
            }
        }

        public int? getInceptTotalTimeout(int month, string userNo)
        {
            if (month == 0 || string.IsNullOrEmpty(userNo))
                return null;
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                var relations = wfDB.PW_DepartmentDutyUserRelation_V.Where(a => a.userNo == userNo).ToList();
                if (relations == null)
                    return null;
                List<WF_InceptTimeoutHistory> results = new List<WF_InceptTimeoutHistory>();
                foreach (var relation in relations)
                {
                    var result = wfDB.WF_InceptTimeoutHistory.Where(a => (a.createTime >= new DateTime(DateTime.Now.Year, month, 1) &&
                        a.createTime < new DateTime(DateTime.Now.Year, month, 1).AddMonths(1) &&
                        a.inceptDuty == relation.dutyNo &&
                        a.inceptDepartment == relation.departmentNo)).ToList();
                    results.AddRange(result);
                }
                results = results.Distinct().ToList();
                if (results.Count == 0)
                    return 0;
                return results.Sum(a => a.inceptResidualTimelimit);
            }
        }


        public List<RP_TransactTimoutCount> getTransactTimeoutCount(string dptNo, DateTime dtFrom, DateTime dtTo)
        {
            using (WFDBDataContext wfDB = new WFDBDataContext(MyConfig.getConnection("myconstring")))
            {
                var ddus = wfDB.PW_DepartmentDutyUserRelation_V.Where(a => a.departmentNo == dptNo).AsEnumerable().Distinct(new MyComparer()).ToList();
                if (ddus == null)
                    return null;
                if (ddus.Count == 0)
                    return null;
                var tcs = new List<RP_TransactTimoutCount>();
                foreach (var ddu in ddus)
                {
                    var timeoutItems = wfDB.WF_TransactTimeoutHistory.Where(a => (a.transactUser == ddu.userNo && a.createTime >= dtFrom && a.createTime <= dtTo)).ToList();
                    var tc = new RP_TransactTimoutCount();
                    tc.userNo = ddu.firstName + "(" + ddu.userNo + ")";
                    tc.counts = timeoutItems.Count;
                    tc.timeoutItems = timeoutItems;
                    tcs.Add(tc);
                }
                return tcs;
            }

        }
    }

    class MyComparer : IEqualityComparer<PW_DepartmentDutyUserRelation_V>
    {
        public bool Equals(PW_DepartmentDutyUserRelation_V x, PW_DepartmentDutyUserRelation_V y)
        {
            if (x == null && y == null)
            {
                return false;
            }
            else
            {
                return x.userNo == y.userNo;
            }
        }

        public int GetHashCode(PW_DepartmentDutyUserRelation_V obj)
        {
            return obj.userNo.GetHashCode();
        }
    }

}
